package com.ecoolex.discount.sales.core.service;

import com.ecoolex.discount.sales.core.external.WeiXinPayExternalService;
import com.ecoolex.discount.sales.core.manager.PaymentOrderManager;
import com.ecoolex.discount.sales.core.manager.PaymentOrderRecordManager;
import com.ecoolex.discount.sales.entity.DiscountOrder;
import com.ecoolex.discount.sales.entity.PaymentOrder;
import com.ecoolex.discount.sales.entity.PaymentOrderRecord;
import com.ecoolex.discount.sales.enums.PaymentOrderRecordOperType;
import com.ecoolex.discount.sales.enums.PaymentOrderRecordResultStatus;
import com.ecoolex.discount.sales.enums.PaymentOrderStatus;
import com.ecoolex.framework.common.enums.ResultCode;
import com.ecoolex.framework.common.util.*;
import com.ecoolex.framework.modularize.api.auth.user.ConsumerMemberManager;
import com.ecoolex.framework.modularize.api.auth.user.ConsumerWeiXinMember;
import com.github.binarywang.wxpay.bean.WxPayApiData;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

@Service
public class WeiXinPayService {

    public static final String PAYMENT_TYPE = "WeiXinPay";

    @Autowired
    private WeiXinPayExternalService weiXinPayExternalService;
    @Autowired
    private ConsumerMemberManager consumerMemberManager;
    @Autowired
    private PaymentOrderManager paymentOrderManager;
    @Autowired
    private PaymentOrderRecordManager paymentOrderRecordManager;

    /*
    支付申请
     */
    public Map payApply(DiscountOrder order, String appId, String ipAdress, String createUser) {
        return paymentOrderManager.paymentApply(order, PAYMENT_TYPE, createUser, (paymentOrder, record) -> {
            // 拼接流水号
            String orderSn = paymentOrder.getBizType() + '-' + paymentOrder.getOrderNo();
            // 获取用户的openId
            List<ConsumerWeiXinMember> weixinList = consumerMemberManager.queryWeiXinByUserId(order.getUserId());
            BizAssert.isTrue(Check.notNullOrEmpty(weixinList), ResultCode.BIZ.build(11), "用户未绑定微信, 无法使用微信支付");
            // 发起支付
            try {
                BigDecimal totalPrice = paymentOrder.getPrepaidPrice();
                // 如果是USD, 则乘以汇率 TODO 没有动态汇率
                if ("USD".equalsIgnoreCase(paymentOrder.getPrepaidCurrencyType())) {
                    // 写死7的汇率
                    totalPrice = totalPrice.multiply(new BigDecimal("7"));
                }
                //  设置支付类型
                record.setCurrencyType("CNY");
                record.setTransAmount(totalPrice);
//                record.setTransNo(orderSn);

                return weiXinPayExternalService.prepay(weixinList.get(0).getOpenId(),
                        orderSn,
                        MessageFormatter.arrayFormat("订单：{}", order.getOrderNo()),
                        order.getCurrencyType(),
                        BigDecimalUtil.dollarToCent(record.getTransAmount()).intValue(),
                        ipAdress);
            } catch (WxPayException e) {
                throw new RuntimeException(e.getMessage(), e);
            } finally {
                // 记录错误日志
                WxPayApiData wxApiData = weiXinPayExternalService.getWxApiData();
                if (Check.notNull(wxApiData)) {
                    record.setRequest(wxApiData.getRequestData());
                    record.setResponse(wxApiData.getResponseData());
                    record.setErrorMessage(wxApiData.getExceptionMsg());
                }
            }
        });
    }

    /*
    检查支付状态
     */
    public void checkPayStatus(PaymentOrder order, String updateUser) {
        // 不是支付中状态不检查
        if (PaymentOrderStatus.PAY_APPLY.notEqual(order.getStatus())) {
            return;
        }

        PaymentOrderRecord log = paymentOrderRecordManager.create(order, PAYMENT_TYPE, PaymentOrderRecordOperType.ORDER_CHECK);
        try {
            // 拼接流水号
            String orderSn = order.getBizType() + '-' + order.getOrderNo();

            WxPayOrderQueryResult payResult = weiXinPayExternalService.getPayResult(orderSn);

            log.setCurrencyType("CNY");
            log.setTransAmount(BigDecimalUtil.centToDollar(BigDecimal.valueOf(payResult.getTotalFee())));
            log.setTransNo(payResult.getTransactionId());

            if (payResult.getTradeState().equalsIgnoreCase("USERPAYING")) {
                // 用户支付中
                log.setResultStatus(PaymentOrderRecordResultStatus.ONGOING.real());
            } else if (payResult.getTradeState().equalsIgnoreCase("SUCCESS")) {
                // 用户支付成功
                log.setTransTime(DateUtil.parseToDate("yyyyMMddHHmmss", payResult.getTimeEnd()));
                log.setResultStatus(PaymentOrderRecordResultStatus.SUCCEED.real());
            } else {
                // 其他原因全为失败
                log.setResultStatus(PaymentOrderRecordResultStatus.FAILED.real());
            }

            paymentOrderManager.updatePayStatusAndNotify(order, log, updateUser);
        } catch (WxPayException e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            WxPayApiData data = weiXinPayExternalService.getWxApiData();
            if (Check.notNull(data)) {
                log.setRequest(data.getRequestData());
                log.setResponse(data.getResponseData());
                log.setErrorMessage(data.getExceptionMsg());
            }
            // 记录调用详情
            paymentOrderRecordManager.add(log, updateUser);
        }
    }

    /*
    付款通知
     */
    public String payNotify(String body, String createUser) {
        try {
            WxPayOrderNotifyResult notifyResult = weiXinPayExternalService.parseOrderNotifyResult(body);
            // 订单号
            String tradeNo = notifyResult.getOutTradeNo();
            int index = tradeNo.indexOf('-');
            String bizType = tradeNo.substring(0, index);
            String orderNo = tradeNo.substring(index + 1);
            PaymentOrder order = paymentOrderManager.getByBizTypeAndOrderNo(bizType, orderNo);
            BizAssert.isTrue(Check.notNull(order), "支付系统中不存在该订单");

            // 检查支付订单的状态, 并生成相应记录
            PaymentOrderRecord log = paymentOrderRecordManager.create(order, PAYMENT_TYPE, PaymentOrderRecordOperType.ORDER_NOTIFY);
            try {
                // 检查通知结果
                weiXinPayExternalService.checkNotifyResult(notifyResult);
                // 如果成功的话, 记录数据
                log.setPaymentType(PAYMENT_TYPE);
                log.setCurrencyType("CNY");
                log.setTransAmount(BigDecimalUtil.centToDollar(BigDecimal.valueOf(notifyResult.getTotalFee())));
                log.setTransNo(notifyResult.getTransactionId());
                log.setTransTime(DateUtil.parseToDate("yyyyMMddHHmmss", notifyResult.getTimeEnd()));
                log.setResultStatus(PaymentOrderRecordResultStatus.SUCCEED.real());
            } catch (Exception e) {
                log.setErrorMessage(e.getMessage());
                log.setResultStatus(PaymentOrderRecordResultStatus.FAILED.real());
            } finally {
                // 记录相应的日志
                log.setRequest(body);
                log.setResponse(weiXinPayExternalService.notifyResult(true, "通知成功"));
                paymentOrderRecordManager.add(log, createUser);
            }

            paymentOrderManager.updatePayStatusAndNotify(order, log, createUser);

            return log.getResponse();
        } catch (Exception e) {
            return weiXinPayExternalService.notifyResult(false, e.getMessage());
        }
    }

    /*
    退款申请
     */
    public void refundApply(PaymentOrder order, PaymentOrderRecord log) {
        try {
            log.setPaymentType(PAYMENT_TYPE);

            String orderSn = order.getBizType() + '-' + order.getOrderNo();
            String refundNo = "r-" + order.getBizType() + '-' + order.getOrderNo();

            WxPayRefundResult result = weiXinPayExternalService.refund(orderSn,
                    refundNo,
                    order.getPaymentCurrencyType(),
                    order.getPaymentPrice(),
                    order.getPaymentPrice());

            log.setPaymentType(PAYMENT_TYPE);
            log.setCurrencyType(order.getPaymentCurrencyType());
            log.setTransAmount(BigDecimalUtil.centToDollar(BigDecimal.valueOf(result.getRefundFee())));
            log.setTransNo(result.getRefundId());
            log.setResultStatus(PaymentOrderRecordResultStatus.SUCCEED.real());
        } catch (WxPayException e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            WxPayApiData data = weiXinPayExternalService.getWxApiData();
            if (Check.notNull(data)) {
                log.setRequest(data.getRequestData());
                log.setResponse(data.getResponseData());
                log.setErrorMessage(data.getExceptionMsg());
            }
        }
    }

    /*
    检查退款状态
     */
    public void checkRefundStatus(PaymentOrder order, String updateUser) {
        // 不是支付中状态不检查
        if (PaymentOrderStatus.REFUND_APPLY.notEqual(order.getStatus())) {
            return;
        }

        PaymentOrderRecord log = paymentOrderRecordManager.create(order, PAYMENT_TYPE, PaymentOrderRecordOperType.REFUND_CHECK);
        log.setPaymentType(PAYMENT_TYPE);
        try {
            String refundNo = "r-" + order.getBizType() + '-' + order.getOrderNo();
            WxPayRefundQueryResult result = weiXinPayExternalService.getRefundResult(refundNo);

            result.getRefundRecords().forEach(record -> {
                // 检查支付订单的状态, 并生成相应记录
                PaymentOrderRecord orderRecord = paymentOrderRecordManager.create(order, PAYMENT_TYPE, PaymentOrderRecordOperType.REFUND_CHECK);

                orderRecord.setPaymentType(PAYMENT_TYPE);
                orderRecord.setCurrencyType(order.getPaymentCurrencyType());
                orderRecord.setTransAmount(BigDecimalUtil.centToDollar(BigDecimal.valueOf(record.getRefundFee())));
                orderRecord.setTransNo(record.getRefundId());

                if (record.getRefundStatus().equalsIgnoreCase("PROCESSING")) {
                    // 用户支付中
                    orderRecord.setResultStatus(PaymentOrderRecordResultStatus.ONGOING.real());
                } else if (record.getRefundStatus().equalsIgnoreCase("SUCCESS")) {
                    // 用户支付成功
                    orderRecord.setTransTime(
                            DateUtil.parseToDate(DateUtil.DEFAULT_DATETIME_FORMAT, record.getRefundSuccessTime()));
                    orderRecord.setResultStatus(PaymentOrderRecordResultStatus.SUCCEED.real());
                } else {
                    // 其他原因全为失败
                    orderRecord.setResultStatus(PaymentOrderRecordResultStatus.FAILED.real());
                }

                // 记录调用详情
                paymentOrderRecordManager.add(orderRecord, updateUser);

                paymentOrderManager.updateRefundStatusAndNotify(order, orderRecord, updateUser);
            });

        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            WxPayApiData data = weiXinPayExternalService.getWxApiData();
            if (Check.notNull(data)) {
                log.setRequest(data.getRequestData());
                log.setResponse(data.getResponseData());
                log.setErrorMessage(data.getExceptionMsg());
            }
            // 记录调用详情
            paymentOrderRecordManager.add(log, updateUser);
        }
    }

    public String refundNotify(String body, String createUser) {
        try {
            WxPayRefundNotifyResult notifyResult = weiXinPayExternalService.parseRefundNotifyResult(body);
            // 订单号
            String tradeNo = notifyResult.getReqInfo().getOutTradeNo();
            int index = tradeNo.indexOf('-');
            String bizType = tradeNo.substring(0, index);
            String orderNo = tradeNo.substring(index + 1);

            PaymentOrder order = paymentOrderManager.getByBizTypeAndOrderNo(bizType, orderNo);
            BizAssert.isTrue(Check.notNull(order), "支付系统中不存在该订单");

            // 检查支付订单的状态, 并生成相应记录
            PaymentOrderRecord log = paymentOrderRecordManager.create(order, PAYMENT_TYPE, PaymentOrderRecordOperType.REFUND_NOTIFY);
            try {
                // 记录退款金额,退款单号
                log.setPaymentType(PAYMENT_TYPE);
                log.setCurrencyType(order.getPaymentCurrencyType());
                log.setTransAmount(BigDecimalUtil.centToDollar(BigDecimal.valueOf(notifyResult.getReqInfo().getRefundFee())));
                log.setTransNo(notifyResult.getReqInfo().getRefundId());

                if (notifyResult.getReqInfo().getRefundStatus().equalsIgnoreCase("SUCCESS")) {
                    log.setTransTime(DateUtil.parseToDate(DateUtil.DEFAULT_DATETIME_FORMAT,
                            notifyResult.getReqInfo().getSuccessTime()));
                    log.setResultStatus(PaymentOrderRecordResultStatus.SUCCEED.real());
                } else {
                    log.setResultStatus(PaymentOrderRecordResultStatus.FAILED.real());
                }
                order.setPaymentNo(log.getTransNo());
                order.setPaymentTime(log.getTransTime());
            } catch (Exception e) {
                log.setErrorMessage(e.getMessage());
                log.setResultStatus(PaymentOrderRecordResultStatus.FAILED.real());
            } finally {
                // 记录相应的日志
                log.setRequest(notifyResult.toString());
                log.setResponse(weiXinPayExternalService.notifyResult(true, "通知成功"));
                paymentOrderRecordManager.add(log, createUser);
            }

            paymentOrderManager.updateRefundStatusAndNotify(order, log, createUser);

            return log.getResponse();
        } catch (Exception e) {
            return weiXinPayExternalService.notifyResult(false, e.getMessage());
        }
    }


}
